

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * TIngresoTeclado 
 */
public class IngresoTeclado {



   /**
    * Es el valor que regresa el metodo peek() cuando esta al final.. es una constante (char)0xFFFF.)
    */
   public final static char EOF = (char)0xFFFF; 

   /**
    * Es el valor que regresa el metodo peek() cuando esta al final de una linea:  '\n'.
    */
   public final static char EOLN = '\n'; 
   

 


   /**
    * Regresa el siguiente caracter de los que acaban de ser ingresados
    * si removerlo de la pila. El caracter puede incluso ser un espacio en blanco.. o el caracter
    * que indique el final del parrafo o linea de texto.
    * @return 
    */
   public static char peek() { 
      return lookChar();
   }
   
   /**
    * Evita los espacio en blanco, exceptuando los finales de linea
    * Luego de haber llamado al metodo, el siguiente caracter  tampoco sera un final de linea, o un espacio vacío.
    */
   public static void skipBlanks() { 
      char ch=lookChar();
      while (ch != EOF && ch != '\n' && Character.isWhitespace(ch)) {
         readChar();
         ch = lookChar();
      }
   }

   private static void skipWhitespace() {
      char ch=lookChar();
      while (ch != EOF && Character.isWhitespace(ch)) {
         readChar();
         if (ch == '\n' && readingStandardInput && writingStandardOutput) {
            out.print("? ");
            out.flush();
         }
         ch = lookChar();
      }
   }

   
   /**
    * Este metodo evita los espacios en blanco y luego lee
    * el valor del texto ingresado, tambien descarta cualquier otro caracter que 
    * sea valido para datos double.
    * @return 
    */
   public static double getlnDouble() { 
      double x=getDouble(); 
      emptyBuffer(); 
      return x; 
   }


   /**
    * Lee todos los caracteres que le usuario ingresa, luego regresa todo lo que se ha ingresado exceptuando 
    * el simbolo de fin de linea.
    * @return 
    */
   public static String getln() {
      StringBuilder s = new StringBuilder(100);
      char ch = readChar();
      while (ch != '\n') {
         s.append(ch);
         ch = readChar();
      }
      return s.toString();
   }

   /**
    * Evita y elimina todos los epspacios en blanco... luego lee el texto ingresado, regresa el ultimo ingresado.
    * Cualquier otro caracter adicional se almanceta y se devuelve en el proxima operacion.
    * @return 
    */
   public static char getChar() { 
      skipWhitespace();
      return readChar();
   }
  
   
   /**
    * Evita y elimina todos los espacios en blanco de un texto, y lee unicamente
    * los correspondientes a un dato double.
    * @return 
    */
   public static double getDouble() {
      double x = 0.0;
      while (true) {
         String str = readRealString();
         if (str == null) {
            errorMessage("Floating point number not found.",
                  "Real number in the range " + (-Double.MAX_VALUE) + " to " + Double.MAX_VALUE);
         }
         else {
            try { 
               x = Double.parseDouble(str); 
            }
            catch (NumberFormatException e) {
               errorMessage("Illegal floating point input, " + str + ".",
                     "Real number in the range " + (-Double.MAX_VALUE) + " to " + Double.MAX_VALUE);
               continue;
            }
            if (Double.isInfinite(x)) {
               errorMessage("Floating point input outside of legal range, " + str + ".",
                     "Real number in the range " + (-Double.MAX_VALUE) + " to " + Double.MAX_VALUE);
               continue;
            }
            break;
         }
      }
      inputErrorCount = 0;
      return x;
   }
   
     
 
   
   private static String inputFileName;  // Name of file that is the current input source, or null if the source is not a file.
   
   
   private final static BufferedReader standardInput = new BufferedReader(new InputStreamReader(System.in));  // wraps standard input stream
   private final static PrintWriter standardOutput = new PrintWriter(System.out);  // wraps standard output stream

   private static BufferedReader in = standardInput;  // Stream that data is read from; the current input source.
   private static PrintWriter out = standardOutput;   // Stream that data is written to; the current output destination.
   
   private static boolean readingStandardInput = true;
   private static boolean writingStandardOutput = true;
   
   private static int inputErrorCount;  // Number of consecutive errors on standard input; reset to 0 when a successful read occurs.
   
   private static Matcher integerMatcher;  // Used for reading integer numbers; created from the integer Regex Pattern.
   private static Matcher floatMatcher;   // Used for reading floating point numbers; created from the floatRegex Pattern.
   private final static Pattern floatRegex = Pattern.compile("(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))((e|E)(\\+|-)?[0-9]+)?");
   
   private static String buffer = null;  // One line read from input.
   private static int pos = 0;           // Position of next char in input line that has not yet been processed.
   
   private static String readRealString() {   // read chars from input following syntax of real numbers
      skipWhitespace();
      if (lookChar() == EOF)
         return null;
      if (floatMatcher == null)
         floatMatcher = floatRegex.matcher(buffer);
      floatMatcher.region(pos,buffer.length());
      if (floatMatcher.lookingAt()) {
         String str = floatMatcher.group();
         pos = floatMatcher.end();
         return str;
      }
      else 
         return null;
   }
   
   
   private static void errorMessage(String message, String expecting) {  // Report error on input.
      if (readingStandardInput && writingStandardOutput) {
             // inform user of error and force user to re-enter.
         out.println();
         out.print("  *** Error in input: " + message + "\n");
         out.print("  *** Expecting: " + expecting + "\n");
         out.print("  *** Discarding Input: ");
         if (lookChar() == '\n')
            out.print("(end-of-line)\n\n");
         else {
            while (lookChar() != '\n')    // Discard and echo remaining chars on the current line of input.
               out.print(readChar());
            out.print("\n\n");
         }
         out.print("Please re-enter: ");
         out.flush();
         readChar();  // discard the end-of-line character
         inputErrorCount++;
         if (inputErrorCount >= 10)
            throw new IllegalArgumentException("Too many input consecutive input errors on standard input.");
      }
      else if (inputFileName != null)
         throw new IllegalArgumentException("Error while reading from file \"" + inputFileName + "\":\n" 
               + message + "\nExpecting " + expecting);
      else
         throw new IllegalArgumentException("Error while reading from inptu stream:\n" 
               + message + "\nExpecting " + expecting);
   }
   
   private static char lookChar() {  // return next character from input
      if (buffer == null || pos > buffer.length())
         fillBuffer();
      if (buffer == null)
         return EOF;
      else if (pos == buffer.length())
         return '\n';
      else 
         return buffer.charAt(pos);
   }
   
   private static char readChar() {  // return and discard next character from input
      char ch = lookChar();
      if (buffer == null) {
         if (readingStandardInput)
            throw new IllegalArgumentException("Attempt to read past end-of-file in standard input???");
         else
            throw new IllegalArgumentException("Attempt to read past end-of-file in file \"" + inputFileName + "\".");
      }
      pos++;
      return ch;
   }
      
   private static void fillBuffer() {    // Wait for user to type a line and press return,
      try {
         buffer = in.readLine();
      }
      catch (Exception e) {
         if (readingStandardInput)
            throw new IllegalArgumentException("Error while reading standard input???");
         else if (inputFileName != null)
            throw new IllegalArgumentException("Error while attempting to read from file \"" + inputFileName + "\".");
         else
            throw new IllegalArgumentException("Errow while attempting to read form an input stream.");
      }
      pos = 0;
      floatMatcher = null;
      integerMatcher = null;
   }
   
   private static void emptyBuffer() {   // discard the rest of the current line of input
      buffer = null;
   }
   

      
} // end of class IngresoTeclado
